define(["require", "exports", "vscode-html-languageservice/parser/htmlScanner", "vscode-html-languageservice/utils/arrays", "vscode-html-languageservice/parser/htmlTags"], function (require, exports, htmlScanner_1, arrays_1, htmlTags_1) {
    /*---------------------------------------------------------------------------------------------
     *  Copyright (c) Microsoft Corporation. All rights reserved.
     *  Licensed under the MIT License. See License.txt in the project root for license information.
     *--------------------------------------------------------------------------------------------*/
    'use strict';
    Object.defineProperty(exports, "__esModule", { value: true });
    var Node = /** @class */ (function () {
        function Node(start, end, children, parent) {
            this.start = start;
            this.end = end;
            this.children = children;
            this.parent = parent;
            this.closed = false;
        }
        Object.defineProperty(Node.prototype, "attributeNames", {
            get: function () { return this.attributes ? Object.keys(this.attributes) : []; },
            enumerable: true,
            configurable: true
        });
        Node.prototype.isSameTag = function (tagInLowerCase) {
            return this.tag && tagInLowerCase && this.tag.length === tagInLowerCase.length && this.tag.toLowerCase() === tagInLowerCase;
        };
        Object.defineProperty(Node.prototype, "firstChild", {
            get: function () { return this.children[0]; },
            enumerable: true,
            configurable: true
        });
        Object.defineProperty(Node.prototype, "lastChild", {
            get: function () { return this.children.length ? this.children[this.children.length - 1] : void 0; },
            enumerable: true,
            configurable: true
        });
        Node.prototype.findNodeBefore = function (offset) {
            var idx = arrays_1.findFirst(this.children, function (c) { return offset <= c.start; }) - 1;
            if (idx >= 0) {
                var child = this.children[idx];
                if (offset > child.start) {
                    if (offset < child.end) {
                        return child.findNodeBefore(offset);
                    }
                    var lastChild = child.lastChild;
                    if (lastChild && lastChild.end === child.end) {
                        return child.findNodeBefore(offset);
                    }
                    return child;
                }
            }
            return this;
        };
        Node.prototype.findNodeAt = function (offset) {
            var idx = arrays_1.findFirst(this.children, function (c) { return offset <= c.start; }) - 1;
            if (idx >= 0) {
                var child = this.children[idx];
                if (offset > child.start && offset <= child.end) {
                    return child.findNodeAt(offset);
                }
            }
            return this;
        };
        return Node;
    }());
    exports.Node = Node;
    function parse(text) {
        var scanner = htmlScanner_1.createScanner(text);
        var htmlDocument = new Node(0, text.length, [], void 0);
        var curr = htmlDocument;
        var endTagStart = -1;
        var pendingAttribute = null;
        var token = scanner.scan();
        while (token !== htmlScanner_1.TokenType.EOS) {
            switch (token) {
                case htmlScanner_1.TokenType.StartTagOpen:
                    var child = new Node(scanner.getTokenOffset(), text.length, [], curr);
                    curr.children.push(child);
                    curr = child;
                    break;
                case htmlScanner_1.TokenType.StartTag:
                    curr.tag = scanner.getTokenText();
                    break;
                case htmlScanner_1.TokenType.StartTagClose:
                    curr.end = scanner.getTokenEnd(); // might be later set to end tag position
                    if (curr.tag && htmlTags_1.isEmptyElement(curr.tag) && curr.parent) {
                        curr.closed = true;
                        curr = curr.parent;
                    }
                    break;
                case htmlScanner_1.TokenType.EndTagOpen:
                    endTagStart = scanner.getTokenOffset();
                    break;
                case htmlScanner_1.TokenType.EndTag:
                    var closeTag = scanner.getTokenText().toLowerCase();
                    while (!curr.isSameTag(closeTag) && curr.parent) {
                        curr.end = endTagStart;
                        curr.closed = false;
                        curr = curr.parent;
                    }
                    if (curr !== htmlDocument) {
                        curr.closed = true;
                        curr.endTagStart = endTagStart;
                    }
                    break;
                case htmlScanner_1.TokenType.StartTagSelfClose:
                    if (curr.parent) {
                        curr.closed = true;
                        curr.end = scanner.getTokenEnd();
                        curr = curr.parent;
                    }
                    break;
                case htmlScanner_1.TokenType.EndTagClose:
                    if (curr.parent) {
                        curr.end = scanner.getTokenEnd();
                        curr = curr.parent;
                    }
                    break;
                case htmlScanner_1.TokenType.AttributeName: {
                    var attributeName = pendingAttribute = scanner.getTokenText();
                    var attributes = curr.attributes;
                    if (!attributes) {
                        curr.attributes = attributes = {};
                    }
                    attributes[pendingAttribute] = null; // Support valueless attributes such as 'checked'
                    break;
                }
                case htmlScanner_1.TokenType.AttributeValue: {
                    var value = scanner.getTokenText();
                    var attributes = curr.attributes;
                    if (attributes && pendingAttribute) {
                        attributes[pendingAttribute] = value;
                        pendingAttribute = null;
                    }
                    break;
                }
            }
            token = scanner.scan();
        }
        while (curr.parent) {
            curr.end = text.length;
            curr.closed = false;
            curr = curr.parent;
        }
        return {
            roots: htmlDocument.children,
            findNodeBefore: htmlDocument.findNodeBefore.bind(htmlDocument),
            findNodeAt: htmlDocument.findNodeAt.bind(htmlDocument)
        };
    }
    exports.parse = parse;
});
